#!/usr/bin/python

import time
import datetime
import logging
from basetask import BaseTask
from utils.errorHelper import ErrorHelper

'''Process engine
'''

class Engine(object):
    '''
    Processing engine
    It works with a context that generated all tasks from config file.
    '''

    def __init__(self, context):
        self._context = context
        self.__logger = logging.getLogger(__name__)

    def start(self):
        self._context.start_time = datetime.datetime.now()
        for task in self._context.get_tasklist():
            self.__logger.info("start to process task '%s'", task.name)
            task.start_time = datetime.datetime.now()
            self._runTask(task, 1) 
            task.finish_time = datetime.datetime.now()
            task.cost = (task.finish_time-task.start_time).total_seconds()
            self.__logger.info("finished to process task '%s', status: %s, cost: %s", task.name, task.status, task.cost)

    def _runTask(self, task:BaseTask, currentRunningTimes):
        if currentRunningTimes == self._context.max_retry_times:
            self.__logger.error("Rearch max retry times")
            return
        try:      
            if currentRunningTimes > 1:
                self.__logger.info("retry task '%s' for the %s times", task.name, currentRunningTimes)
            task.process(self._context)
            if task.verify(self._context):
                task.status = 'succeed'
            else: 
                task.status = 'failed to verify'
        except Exception:
            task.error = ErrorHelper.format_exception()
            task.status = "failed with exception"
            self.__logger.error("got exception to process task '%s'.", task.name, exc_info=True)
            time.sleep(30 * currentRunningTimes)
            self._runTask(task, currentRunningTimes + 1)


class Context(object):
    '''processing context
    '''

    def __init__(self):
        self._task_list = []
        self.start_time = datetime.datetime.now()
        self.finish_time = None
        self.errors = []
        self.max_retry_times = 3
        self.args = []

    def get_tasklist(self):
        return self._task_list

    def add_task(self, task):        
        if task not in self._task_list:
            self._task_list.append(task)

    def remove_task(self, task):
        self._task_list.remove(task)

    def finalize_tasks(self):
        '''
        finalize tasks by sorting by priority
        '''
        self._task_list = sorted(self._task_list, key=lambda task : task.priority)